package com.decent.common.config.advice;

import com.decent.common.bo.MessageBean;
import com.decent.common.enums.ErrorCodeEnum;
import com.decent.common.exception.ErrorCodeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;

/**
 * @author wangyan
 * @date 2002/03/24
 */
@SuppressWarnings("unused")
@Slf4j
public abstract class BaseExceptionHandler {

    /**
     * 异常兜底，需要加Tracer所以只能在继承处实现
     *
     * @param request HttpServletRequest
     * @param ex      Exception
     * @return 结果
     * * @ExceptionHandler(value = Exception.class) *
     * * @ResponseBody *
     */
    public abstract MessageBean errorHandler(HttpServletRequest request, Exception ex);

    /**
     * 自定义异常
     *
     * @param request 请求
     * @param e       异常
     * @return 返回值
     */
    @ExceptionHandler(value = ErrorCodeException.class)
    @ResponseBody
    public MessageBean errorCodeHandler(HttpServletRequest request, ErrorCodeException e) {
        MessageBean message = new MessageBean();
        log.warn("[{}]接口异常[{}]", request.getRequestURI(), e.getMessage(), e);
        message.setCode(e.getCode());
        message.setMessage(e.getMessage());
        return message;
    }

    /**
     * 参数校验异常 BindException
     *
     * @param request 请求
     * @param e       异常
     * @return MessageBean
     */
    @ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class})
    @ResponseBody
    public MessageBean methodArgumentNotValidExceptionHandler(HttpServletRequest request, Exception e) {
        BindingResult bindingResult;
        String errorMsg;
        if (e instanceof MethodArgumentNotValidException) {
            bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            errorMsg = bindingResult.getAllErrors().listIterator().next().getDefaultMessage();
        } else if (e instanceof ConstraintViolationException) {
            errorMsg = ((ConstraintViolationException) e).getConstraintViolations().iterator().next().getMessage();
        } else if (e instanceof BindException) {
            bindingResult = ((BindException) e).getBindingResult();
            errorMsg = bindingResult.getAllErrors().listIterator().next().getDefaultMessage();
        } else {
            errorMsg = ErrorCodeEnum.INVALID_PARAMS.getMessage();
        }
        MessageBean message = new MessageBean();
        log.warn("[{}]接口参数异常[{}]", request.getRequestURI(), errorMsg);
        message.setCode(ErrorCodeEnum.INVALID_PARAMS.getCode());
        message.setMessage(errorMsg);
        return message;
    }

    /**
     * HttpRequestMethodNotSupportedException 请求方法不受支持异常
     *
     * @param request 请求
     * @param ex      异常
     * @return MessageBean
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public MessageBean httpRequestMethodNotSupportedException(HttpServletRequest request, Exception ex) {
        MessageBean message = new MessageBean();
        log.warn("[{}]请求方法不受支持", request.getRequestURI(), ex);
        message.setCode(ErrorCodeEnum.REQUEST_METHOD_NOT_SUPPORTED.getCode());
        message.setMessage(ErrorCodeEnum.REQUEST_METHOD_NOT_SUPPORTED.getMessage());
        return message;
    }

    /**
     * 数字转换异常 NumberFormatException
     *
     * @param request 请求
     * @param e       异常
     * @return MessageBean
     */
    @ExceptionHandler(value = NumberFormatException.class)
    @ResponseBody
    public MessageBean numberFormatExceptionHandler(HttpServletRequest request, NumberFormatException e) {
        log.warn("[{}]接口参数异常[{}]", request.getRequestURI(), e.getLocalizedMessage(), e);
        return new MessageBean(ErrorCodeEnum.INVALID_PARAMS);
    }
}
